<!--
 * @Author: 四川华西绿舍建材有限公司
 * @Date: 2023-11-17 13:29:46
 * @LastEditors: 陈波
 * @LastEditTime: 2024-04-01 12:09:10
 * @Description: 
 * @FilePath: \graDesign\src\views\SAC\SACAlgorithmCompare\index.vue
-->
<template>
  <div class="home">
    <LayoutIndex>
      <el-button 
        type="primary" 
        plain 
        @click="open"
      >参数设置并生成模型</el-button>
    </LayoutIndex>

    <LayoutDetail>
      <div class="demoCharts">
        <div v-if="showChart">
          <div class="chartItem">
            <BasicCharts
              :option="option1"
              :carouselNum="carouselNum"
            />
          </div>
          <el-divider style="margin: 20px 0;">
            <el-icon><star-filled /></el-icon>
            <el-icon><star-filled /></el-icon>
            <el-icon><star-filled /></el-icon>
          </el-divider>
          <div class="chartItem">
            <BasicCharts
              :option="option2"
              :carouselNum="carouselNum"
            />
          </div>
          <el-divider style="margin: 20px 0;">
            <el-icon><star-filled /></el-icon>
            <el-icon><star-filled /></el-icon>
            <el-icon><star-filled /></el-icon>
          </el-divider>
          <div class="chartItem">
            <BasicCharts
              :option="option3"
              :carouselNum="carouselNum"
            />
          </div>
        </div>
        <div class="flex_center" v-else>
          <el-image
            style="width: 65%; height: 65%"
            :src="SACCompare"
            fit="fill"
          />
        </div>
      </div>
    </LayoutDetail>

    <!-- 修改参数对话框 -->
    <BasicDialog
      :visible="paramsDialogVisible"
      width="55%"
      :showClose="true"
      :hasHeadDivider="true"
      :hasFooterDivider="true"
      @handleClose="close"
    >
      <template #header>
        <div slot="header">
          Set Params(参数设置)
        </div>
      </template>
      <el-form
        ref="ruleFormRef"
        :model="ruleForm"
        :rules="rules"
        label-width="180"
        status-icon
      >
        <el-row :gutter="20">
          <el-col :span="11">
            <el-form-item label="最大回合数:" prop="max_episodes">
              <el-input type="number" v-model="ruleForm.max_episodes" clearable />
            </el-form-item>
          </el-col>
          <el-col :span="11">
            <el-form-item label="每回合的最大步数:" prop="max_steps">
              <el-input type="number" v-model="ruleForm.max_steps" clearable />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="11">
            <el-form-item label="批次大小:" prop="batch_size">
              <el-input type="number" v-model="ruleForm.batch_size" clearable />
            </el-form-item>
          </el-col>
          <el-col :span="11">
            <el-form-item label="迭代次数:" prop="update_itr">
              <el-input type="number" v-model="ruleForm.update_itr" clearable />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="11">
            <el-form-item label="隐藏层维度:" prop="hidden_dim">
              <el-input type="number" v-model="ruleForm.hidden_dim" clearable />
            </el-form-item>
          </el-col>
          <el-col :span="11">
            <el-form-item label="策略目标更新间隔:" prop="policy_target_update_interval">
              <el-input type="number" v-model="ruleForm.policy_target_update_interval" clearable />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="11">
            <el-form-item label="是否使用确定性策略:" prop="deterministic">
              <vxe-radio v-model="ruleForm.deterministic" :label="true" content="是" />
              <vxe-radio v-model="ruleForm.deterministic" :label="false" content="否" />
            </el-form-item>
          </el-col>
          <el-col :span="11">
            <el-form-item label="探索噪声比例:" prop="explore_noise_scale">
              <el-input 
                type="number" 
                v-model="ruleForm.explore_noise_scale" 
                clearable
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="11">
            <el-form-item label="评估噪声比例:" prop="eval_noise_scale">
              <el-input type="number" v-model="ruleForm.eval_noise_scale" clearable />
            </el-form-item>
          </el-col>
          <el-col :span="11">
            <el-form-item label="奖励缩放因子:" prop="reward_scale">
              <el-input type="number" v-model="ruleForm.reward_scale" clearable />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="11">
            <el-form-item label="时间帧索引:" prop="frame_idx">
              <el-input type="number" v-model="ruleForm.frame_idx" clearable disabled />
            </el-form-item>
          </el-col>
          <el-col :span="11">
            <el-form-item label="设备数:" prop="n_index">
              <el-input type="number" v-model="ruleForm.n_index" clearable />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
        <span slot="footer" class="dialog-footer">
          <el-button @click="close">取 消</el-button>
          <el-button type="success" @click="handleSubmit(ruleFormRef)">确 定</el-button>
        </span>
      </template>
    </BasicDialog>
  </div>
</template>

<script setup lang="ts">
import dataSourceApi from '@/request/api/dataSource'
import { ref, reactive, inject } from 'vue'
import type { FormInstance, FormRules } from "element-plus";
import { showMessageBox } from '@/utils/alertMsg';
import SACCompare from '@/assets/images/home/SACCompare.png'


let paramsDialogVisible = ref<boolean>(false)

const showLayoutLoading: Function = inject('showLayoutLoading');
const hideLayoutLoading: Function = inject('hideLayoutLoading');

interface RuleForm {
  max_episodes: number,                     // 设置最大回合数
  max_steps: number,                        // 设置每回合的最大步数
  batch_size: number,                       // 设置批次大小
  update_itr: number,                       // 设置更新迭代次数
  hidden_dim: number,                       // 设置隐藏层维度
  policy_target_update_interval: number,    // 设置策略目标更新间隔
  deterministic: boolean,                   // 设置是否使用确定性策略
  explore_noise_scale: number,              // 设置探索噪声比例
  eval_noise_scale: number,                 // 设置评估噪声比例
  reward_scale: number,                     // 设置奖励缩放因子
  frame_idx: number,                        // 设置当前帧索引
  n_index: number                           // 设备数量
}

const ruleFormRef = ref<FormInstance>();
const ruleForm = reactive<RuleForm>({
  max_episodes: 10,  
  max_steps: 20,    
  batch_size: 45,   
  update_itr: 1,   
  hidden_dim: 512, 
  policy_target_update_interval: 10,
  deterministic: true, 
  explore_noise_scale: 0.1,
  eval_noise_scale: 0.5, 
  reward_scale: 1,
  frame_idx: 0,
  n_index: 40
})

const rules = reactive<FormRules<RuleForm>>({
  max_episodes: [
    { required: true, trigger: "blur" }
  ],
  max_steps: [
    { required: true, trigger: "blur" }
  ],
  batch_size: [
    { required: true, trigger: "blur" }
  ],
  update_itr: [
    { required: true, trigger: "blur" }
  ],
  hidden_dim: [
    { required: true, trigger: "blur" }
  ],
  policy_target_update_interval: [
    { required: true, trigger: "blur" }
  ],
  deterministic: [
    { required: true, trigger: "blur" }
  ],
  explore_noise_scale: [
    { required: true, trigger: "blur" }
  ],
  eval_noise_scale: [
    { required: true, trigger: "blur" }
  ],
  reward_scale: [
    { required: true, trigger: "blur" }
  ],
  frame_idx: [
    { required: true, trigger: "blur" }
  ],
  n_index: [
    { required: true, trigger: "blur" }
  ]
});

interface seriesDataItem {
  name: string
  type: string
  data: Array<number>
  smooth: boolean
}

let showChart = ref<boolean>(false);
const carouselNum = ref<number>(0);
const drawChart = async () => {
  showLayoutLoading();
  const LstmRes: any = await dataSourceApi.getSACDataSourceByLSTM(ruleForm);
  // console.log('LstmRes:', LstmRes)
  
  const R2N2Res: any = await dataSourceApi.getSACDataSourceByR2N2(ruleForm).catch(() => {
    hideLayoutLoading();
    showMessageBox('error', '算法调用失败，请检查网络后重试！');
  }).finally(() => {
    hideLayoutLoading();
    showChart.value = true;
  });
  // console.log('R2N2Res:', R2N2Res)

  // 1. 修改option1：对比Rewards
  // 数据数组
  const tempSeriesArr1 = ref<Array<seriesDataItem>>([])
  // x轴坐标
  const xAxisData = ref<Array<string>>([]);
  // 每条折线名称
  const seriesNames1 = ref<Array<string>>([]);
  // 2. 修改option2：对比T_round_delay
  // 数据数组
  const tempSeriesArr2 = ref<Array<seriesDataItem>>([])
  // 每条折线名称
  const seriesNames2 = ref<Array<string>>([]);
  // 3. 修改option3：对比T_round_delay
  // 数据数组
  const tempSeriesArr3 = ref<Array<seriesDataItem>>([])
  // 每条折线名称
  const seriesNames3 = ref<Array<string>>([])

  for(const key in LstmRes) {
    const retrievedKeys1 = ['rewards', 'rewards_zhuanzhi'];
    const retrievedKeys2 = ['device_energy_consumption', 'fl_accuracy', 'fl_penalty'];
    const retrievedKeys3 = ['T_round_delay'];
    if(retrievedKeys1.includes(key)) {
      tempSeriesArr1.value.push({
        name: `SAC_LSTM: ${key}`,
        type: 'line',
        data: LstmRes[key],
        smooth: true
      })
      seriesNames1.value.push(`SAC_LSTM: ${key}`);
    }
    if(retrievedKeys2.includes(key)) {
      tempSeriesArr2.value.push({
        name: `SAC_LSTM: ${key}`,
        type: 'line',
        data: LstmRes[key],
        smooth: true
      })
      seriesNames2.value.push(`SAC_LSTM: ${key}`);
    }
    if(retrievedKeys3.includes(key)) {
      tempSeriesArr3.value.push({
        name: `SAC_LSTM: ${key}`,
        type: 'line',
        data: LstmRes[key],
        smooth: true
      })
      seriesNames3.value.push(`SAC_LSTM: ${key}`);
    }
  }
  for(const key in R2N2Res) {
    const retrievedKeys1 = ['rewards', 'rewards_zhuanzhi'];
    const retrievedKeys2 = ['device_energy_consumption', 'fl_accuracy', 'fl_penalty'];
    const retrievedKeys3 = ['T_round_delay'];
    if(retrievedKeys1.includes(key)) {
      tempSeriesArr1.value.push({
        name: `SAC_R2N2: ${key}`,
        type: 'line',
        data: R2N2Res[key],
        smooth: true
      })
      seriesNames1.value.push(`SAC_R2N2: ${key}`);
    }
    if(retrievedKeys2.includes(key)) {
      tempSeriesArr2.value.push({
        name: `SAC_R2N2: ${key}`,
        type: 'line',
        data: R2N2Res[key],
        smooth: true
      })
      seriesNames2.value.push(`SAC_R2N2: ${key}`);
    }
    if(retrievedKeys3.includes(key)) {
      tempSeriesArr3.value.push({
        name: `SAC_R2N2: ${key}`,
        type: 'line',
        data: R2N2Res[key],
        smooth: true
      })
      seriesNames3.value.push(`SAC_R2N2: ${key}`);
    }
  }
  for(let i = 0; i < LstmRes.rewards.length; i++) {
    xAxisData.value.push(i.toString());
  }
  // 赋值
  option1.value.xAxis.data = xAxisData.value;
  option1.value.legend.data = seriesNames1.value;
  option1.value.series = tempSeriesArr1.value;

  option2.value.xAxis.data = xAxisData.value;
  option2.value.legend.data = seriesNames2.value;
  option2.value.series = tempSeriesArr2.value;

  option3.value.xAxis.data = xAxisData.value;
  option3.value.legend.data = seriesNames3.value;
  option3.value.series = tempSeriesArr3.value;
}
const open = () => {
  paramsDialogVisible.value = true;
}
const close = () => {
  paramsDialogVisible.value = false;
}

const handleSubmit = async (formEl: FormInstance | undefined) => {
  if (!formEl) return
  await formEl.validate((valid, fields) => {
    if (valid) {
      // showMessageBox('success', 'valid', 3000, false);
      // 将对象的所有键值转换成数字类型
      Object.keys(ruleForm).forEach(key => {
        if(key != 'deterministic') {
          ruleForm[key] = parseFloat(ruleForm[key]);
        }
      });
      drawChart();
      close()
    } else {
      showMessageBox('error', 'Invalid Input', 3000, false);
    }
  })
}

// 折线图 - Rewards Compare Line
let option1 = ref<any>({
  title: {
    text: 'Rewards Compare Line'
  },
  tooltip: {
    trigger: 'axis'
  },
  legend: {
    data: [],
    textStyle: {
      color: '#000'
    }
  },
  grid: {
    left: '3%',
    right: '4%',
    bottom: '3%',
    containLabel: true
  },
  xAxis: {
    name: '轮次',
    type: 'category',
    boundaryGap: false,
    data: []
  },
  yAxis: {
    name: '',
    type: 'value',
  },
  series: []
});

// 折线图 - ['fl_accuracy', 'fl_penalty', 'device_energy_consumption'] Compare Line
let option2 = ref<any>({
  title: {
    text: 'Output Compare Line'
  },
  tooltip: {
    trigger: 'axis'
  },
  legend: {
    data: [],
    right: '3%',
    top: '3%',
    textStyle: {
      color: '#000'
    }
  },
  grid: {
    left: '3%',
    right: '4%',
    bottom: '3%',
    containLabel: true
  },
  xAxis: {
    name: '轮次',
    type: 'category',
    boundaryGap: false,
    data: []
  },
  yAxis: {
    name: '',
    type: 'value',
  },
  series: []
});

// 折线图 - T_round_delay Compare Line
// 每个训练轮次的延迟时间
let option3 = ref<any>({
  title: {
    text: 'T_round_delay Compare Line'
  },
  tooltip: {
    trigger: 'axis'
  },
  legend: {
    data: [],
    textStyle: {
      color: '#000'
    }
  },
  grid: {
    left: '3%',
    right: '4%',
    bottom: '3%',
    containLabel: true
  },
  xAxis: {
    name: '轮次',
    type: 'category',
    boundaryGap: false,
    data: []
  },
  yAxis: {
    name: '',
    type: 'value',
  },
  series: []
});
</script>

<style scoped lang="scss">
.demoCharts {
  // height: 100vh;
  // border: 1px solid red;
  .chartItem {
    height: 600px;
    margin: 20px 0;
  }
}
.el-form-item {
  margin: .625rem 0;
}
</style>